<?php

// | Copyright (c) 2019~2020 http://jiunidu.com All rights reserved.
// +----------------------------------------------------------------------
// | Author: huanglijun <80792275@qq.com>
// +----------------------------------------------------------------------

namespace service\pay;


use app\common\model\CouponCode;
use app\group\model\GroupOrderModel;
use app\funding\model\FundingOrder;
use app\order\model\Order;
use think\Exception;
use think\facade\Log;
use think\facade\Request;
use service\tools\http\Curl;
use service\pay\WxPay;
use service\pay\PayDb;
use think\facade\Env;
use service\pay\VirtualPay;
use app\activity\model\RefundcoModel;
use app\property\model\PropertySubscribe;
use service\Distribution;
use service\OrderReturnService;
use app\decoration\model\RefundModel;


class PayService
{

    //支付对象
    protected $pay=null;
    //支付回调
    protected $pay_notify_url          =   "/pay_notity";
    //退款支付回调
    protected $refund_notify_url       =   "/refund_notity";

    public function __construct()
    {
        $this->pay_notify_url       =   Env::get('app.callback_host').$this->pay_notify_url;
        $this->refund_notify_url    =   Env::get('app.callback_host').$this->refund_notify_url;
    }

    //订单类型  1 商品 2 拼团 3 众筹 4 活动 5 装修 6 线下购 7线上预约 8 楼盘认筹
    protected $order_type_body=[
                                '1'=>"商品",
                                '2'=>"拼团",
                                '3'=>"众筹",
                                '4'=>"活动",
                                '5'=>"装修",
                                '6'=>"线下购",
                                '7'=>"线上预约",
                                '8'=>'楼盘认筹',
                               ];
    //各订单，处理支付回调的方法模型
    protected $pay_notity_url=[
                                '1'=>"OrderModel",
                                '2'=>"拼团",
                                '3'=>"众筹",
                                '4'=>"活动",
                                '5'=>"装修",
                                '6'=>"线下购",
                                '7'=>"线上预约",
                                '8'=>"楼盘认筹",
                               ];
    //返回的数据格式1000：表示成功，其他表示失败，message提示的信息,$data,返回的数据数组
    public $return_ok=['code'=>1000,'message'=>"操作成功",'data'=>[]];
    public $return_fail=['code'=>2000,'message'=>"操作失败",'data'=>[]];

    /**
     * 生成支付记录
     *
     * @param int $pay_platform  支付方式  1->自平台 2->微信 3->支付宝 4->银联
     * @param int $order_id      业务订单编号，平台内唯一
     * @param int $user_id       用户ID
     * @param int $pay_fee       支付金额 ，单位:分
     * @param int $coin_fee      支付金币 ，单位:分
     * @param int $order_type    订单类型
     * @param int $pay_psw       支付密码
     *
     * @return array  返回数组，不同平台返回数组不同
     */
    public function CreatePay($pay_platform=0,$order_id=0,$user_id=0,$pay_fee=0,$coin_fee=0,$order_type=0,$pay_psw="")
    {

        if(empty($pay_platform)||empty($order_id)
         ||empty($user_id)||empty($pay_fee))
        {
            $this->return_fail['message']='必填字段为空!';
            return $this->return_fail;
        }
        if(!array_key_exists($order_type, $this->order_type_body))
        {
            $this->return_fail['message']='订单类型错误';
            return $this->return_fail;
        }
        $this->return_ok['data']['wxpay_params']=(object)array();
        $pay_db=new PayDb();
        //获取用户信息
        $user_info=$pay_db->get_user_info($user_id,"user_wx_openid,user_balance,user_gold,user_pay_psw");
        if(empty($user_info))
        {
            $this->return_fail['message']='用户信息错误';
            return $this->return_fail;
        }
        //获取支付信息
        $pay_info=$pay_db->get_pay_info($order_id,"payed");
        if(!empty($pay_info))
        {
            if($pay_info['payed']===2 || $pay_info['payed']===3)
            {
                $this->return_fail['message']='此订单支付已支付或者异常';
                return $this->return_fail;
            }
        }
        //计算最终抵扣的金币，及最终支付的订单额
        $user_balance=bcmul($user_info['user_balance'],100,2);
        $user_gold=bcmul($user_info['user_gold'],100,2);
        //最终使用多少金币抵扣
        if((float)$user_gold<$coin_fee)
        {
            $use_coin_fee=$user_gold;
        }
        else
        {
            $use_coin_fee=$coin_fee;
        }
        $final_pay_fee=bcsub($pay_fee,$use_coin_fee,2);


        //自有平台支付
        if($pay_platform==1)
        {

            if(empty($user_info['user_pay_psw'])||empty($pay_psw)
            ||!password_verify($pay_psw,$user_info['user_pay_psw']))
            {
                $this->return_fail['code']=2001;
                $this->return_fail['message']='支付密码错误！';
                return $this->return_fail;
            }
            //密码正确，扣除金币及余额
            $balance_num=bcdiv($final_pay_fee,100,2);
            $coin_num=bcdiv($use_coin_fee,100,2);

            //支付记录入库处理
            $data['order_id']=$order_id;
            $data['user_id']=$user_id;
            $data['order_type']=$order_type;
            $data['pay_fee']=0;
            $data['coin_fee']=$use_coin_fee;
            $data['balance_fee']=$final_pay_fee;
            $data['add_time']=time();
            $data['update_time']=time();
            $return_pay_id=$pay_db->update_pay_data($data);
            //支付记录更新成功
            if((int)$return_pay_id>0)
            {
                $pay_type=0;
                if($balance_num>0)
                {
                    $pay_type=1;     
                }
                if($coin_num>0)
                {
                    $pay_type=2;     
                }
                if($balance_num>0 && $coin_num>0 )
                {
                    $pay_type=3; 
                }


                $virtual_pay=new VirtualPay();
                $return_id=$virtual_pay->update_user_virtual($user_id,'',2,$pay_type,$balance_num,$coin_num);
                if((int)$return_id>0)
                {
                    $this->return_ok['data']['pay_type']=1;
                    $this->return_ok['data']['pay_status']="yes";
                    //余额支付通知
                    $return_notity=$this->PayNotity(1,1,$order_type,$order_id);
                    return $this->return_ok;
                }
            }
            return $this->return_fail;
        }


        //如果当前用户余额满足支付订单，则全部用余额支付
        if($final_pay_fee<=$user_balance)
        {

            $this->return_ok['data']['pay_status']="no";
            $this->return_ok['data']['pay_type']=1;
            return $this->return_ok;
        }

        //微信支付
        if($pay_platform==2)
        {
            $final_pay_fee=$final_pay_fee-$user_balance;

            $this->pay=new WxPay();
            $this->pay->pay_notify_url=$this->pay_notify_url;
            $this->pay->open_id=$user_info['user_wx_openid'];
            //保存订单类型，回调方便分发回调信息
            $this->pay->attach=$order_type;
            $this->pay->setOrderBody($this->order_type_body[$order_type]);
            $this->pay->setPayFee($final_pay_fee);
            $this->pay->setOrderId($order_id);
            $this->pay->set_pay_platform($pay_platform);
            //微信预付款ID
            $return=$this->pay->unifiedOrder();
            if(!empty($return))
            {
                $this->return_ok['data']['wxpay_params']=$this->pay->getPayParams();
                //1->平台支付 2->第三方支付 3->混合支付(平台和第三方支付)  1需要调起平台内支付密码验证，验证通过后
                $this->return_ok['data']['pay_type']=2;
                $this->return_ok['data']['pay_status']="no";
                //入库处理
                $data['order_id']=$order_id;
                $data['user_id']=$user_id;
                $data['prepay_id']=$return['prepayId'];
                $data['order_type']=$order_type;
                $data['pay_fee']= $final_pay_fee;
                $data['coin_fee']=$use_coin_fee;
                $data['balance_fee']=$user_balance;
                $data['add_time']=time();
                $data['update_time']=time();
                $return_id=$pay_db->update_pay_data($data);
                if((int)$return_id>0)
                {
                    //处理成功后返回
                    return $this->return_ok;
                }
            }
            $this->return_fail['message']='微信生成预付订单失败';
            return $this->return_fail;
        }
        $this->return_fail['message']='参数错误';
        return $this->return_fail;

    }

    /**
     * 生成退款记录
     *
     * @param int $order_id             业务订单编号，平台内唯一
     * @param int $refund_id            退订订单号
     * @param int $user_id              用户ID
     * @param int $order_type           订单类型  1 商品 2 拼团 3 众筹 4 活动 5 装修 6 线下购 7线上预约 8 楼盘认筹
     *
     * @return bool                    是否成功
     */
    public function CreateRefund($order_id=0,$refund_id=0,$user_id=0,$order_type=0)
    {
        Log::info('RefundNotify backend:createRefund');
        if(empty($order_id)||empty($refund_id)
         ||empty($user_id))
        {
            $this->return_fail['message']='必填字段为空!';
            return false;
        }
        if(!array_key_exists($order_type, $this->order_type_body))
        {
            $this->return_fail['message']='订单类型错误';
            return false;
        }
        $this->return_ok['data']['wxpay_params']=(object)array();
        $pay_db=new PayDb();
        //获取用户信息
        $user_info=$pay_db->get_user_info($user_id,"user_wx_openid,user_balance,user_gold,user_pay_psw");
        if(empty($user_info))
        {
            $this->return_fail['message']='用户信息错误';
            return false;
        }
        //获取支付信息
        $pay_info=$pay_db->get_pay_info($order_id,"payed,pay_fee,coin_fee,balance_fee,remark");
        if(!empty($pay_info))
        {
            if($pay_info['payed']!==2)
            {
                $this->return_fail['message']='此订单不可以退款!';
                return false;
            }
            //获取退款信息
            $refund_info=$pay_db->get_refund_info($order_id,$refund_id,"refunded");
            if(!empty($refund_info))
            {
                if($refund_info['refunded']==2)
                {
                    $this->return_fail['message']='此订单的退款订单号已经退款了';
                    return false;
                }
            }

        }

        
        
        //入库处理
        $data['order_id']=$order_id;
        $data['refund_id']=$refund_id;
        $data['user_id']=$user_id;
        $data['refunded']=1;
        $data['order_type']=$order_type;
        $data['refund_pay_fee']= $pay_info['pay_fee'];
        $data['refund_coin_fee']=$pay_info['coin_fee'];
        $data['refund_balance_fee']=$pay_info['balance_fee'];
        $data['add_time']=time();
        $data['update_time']=time();
        $data['remark']=$pay_info['remark']."退款";
        
        $return_id=$pay_db->update_refund_data($data);
        //Log::info("return_id:" . $refund_id);die;
        
        if((int)$return_id<=0)
        {
            //处理成功后返回
            return false;
        }

        // 优惠券返还
        //$this->returnCoupon($order_id);
        
        //使用了第三方支付
        if($pay_info['pay_fee']>0)
        {
            Log::info('RefundNotify backend:third pay');
            //Log::info('第三方');
            $this->pay=new WxPay();
            $this->pay->refund_notify_url=$this->refund_notify_url;
            $this->pay->open_id=$user_info['user_wx_openid'];
            //保存订单类型，回调方便分发回调信息
            $this->pay->attach=$order_type;
            $this->pay->setOrderBody($this->order_type_body[$order_type]);
            $this->pay->setPayFee($pay_info['pay_fee']);
            $this->pay->setRefundFee($pay_info['pay_fee']);
            $this->pay->setOrderId($order_id);
            $this->pay->setRefundId($refund_id);
            // $this->pay->set_pay_platform($pay_platform);
            //微信预付款ID
            $yesno_refund=$this->pay->unifiedOrderRefund();
            Log::info("微信退款".print_r($yesno_refund,true));
            if($yesno_refund) return true;

        }
        //没有使用第三方支付
        if($pay_info['pay_fee']==0)
        {
            Log::info('RefundNotify backend:self pay');
            //Log::info('余额支付');
          //余额支付通知
          $yesno_refund=$this->RefundNotity(1,1,$order_type,$order_id,$refund_id);
          //Log::info('returnNotify result:' . $yesno_refund);
          Log::info("余额退款".print_r($yesno_refund,true));
          if($yesno_refund) return true;
        }

        return false;
    }
    
   
    
    /**
     * 获取回调基本数据
     */
    public function getPayBaseData($order_id='')
    {
        $return_array=[];
        if(empty($order_id))
        {
            return $return_array;
        }
        //获取支付信息
        $pay_db=new PayDb();
        $return_array=$pay_db->get_pay_info($order_id,"order_id,user_id,pay_fee,coin_fee,balance_fee,remark");
        return $return_array;
    }
    /**
     * 获取退款回调基本数据
     */
    public function getRefundBaseData($order_id='',$refund_id='')
    {
        $return_array=[];
        if(empty($order_id) || empty($refund_id))
        {
            return $return_array;
        }
        //获取支付信息
        $pay_db=new PayDb();
        $return_array=$pay_db->get_refund_info($order_id,$refund_id,"order_id,user_id,refunded,refund_id,refund_pay_fee,refund_coin_fee,refund_balance_fee,remark");
        return $return_array;
    }
    /**
     * 支付回调处理
     */
    public function PayNotity($pay_platform=0,$yesno=0,$order_type=0,$order_id=0)
    {
        $return_notity=false;
        $notity_data=['base_data'=>[],'other_data'=>[]];
        $pay_type=0;
        Log::info("余额支付:".$pay_platform.$order_type.$order_id.$yesno);
        //处理微信回调
        if($pay_platform==1)
        {
            $yesno=1;
            $pay_type=1;
            $base_data=$this->getPayBaseData($order_id);
            $notity_data['base_data']=$base_data;
            $notity_data['other_data']=[];
        }
        //处理微信回调
        if($pay_platform==2)
        {
            $this->pay=new WxPay();
            //验证签名信息
            $yesno=$this->pay->check_notify_sign();
            //验证成功,分发回调数据到具体业务逻辑
            Log::info("微信回调签名结果".$this->pay->notice_result_msg);

            if($yesno==true)
            {
                Log::info("微信回调数据数组".print_r($this->pay->request_data,true));
                $yesno=1;
                $pay_type=2;
                $base_data=$this->getPayBaseData($this->pay->request_data['out_trade_no']);
                if(empty($base_data))
                {
                    $yesno=2;
                }
                $notity_data['base_data']=$base_data;
                $notity_data['other_data']=$this->pay->request_data;
                $order_type=$this->pay->request_data['attach'];
                Log::info("平台回调数据数组".print_r($notity_data,true));
                //判断是否需要调用平台支付系统，平台目前优先余额、金币强制全额支付
                //平台支付系统成功，把成功信息分发到业务，如果失败，分发错误信息
                //具体业务逻辑处理成功，则返回微信成功信息
                $pay_type=0;
                if($base_data['balance_fee']>0)
                {
                    $pay_type=1;
                    $balance_fee=bcdiv($base_data['balance_fee'],100,2);     
                }
                if($base_data['coin_fee']>0)
                {
                    $pay_type=2;   
                    $coin_fee=bcdiv($base_data['coin_fee'],100,2);   
                }
                if($base_data['balance_fee']>0 && $base_data['coin_fee']>0 )
                {
                    $pay_type=3; 
                    $balance_fee=bcdiv($base_data['balance_fee'],100,2); 
                    $coin_fee=bcdiv($base_data['coin_fee'],100,2);
                }

                $virtual_pay=new VirtualPay();
                $return_id=$virtual_pay->update_user_virtual($base_data['user_id'],'',2,$pay_type,$balance_fee,$coin_fee);
                //平台支付失败，分发到业务逻辑失败
                if($return_id==-1)
                {
                    $yesno=2;
                }
            }
            //返回微信错误信息
        }

        //回调分发 订单类型  1 商品 2 拼团 3 众筹 4 活动 5 装修 6 线下购 7线上预约 8 楼盘认筹
        switch ($order_type)
        {
            case 1:
                $order = new Order();
                $return_notity=$order->PayNotity($yesno,$pay_type,$notity_data);
            break;
            case 2:
                $group = new GroupOrderModel();
                $return_notity=$group->PayNotity($yesno,$pay_type,$notity_data);
                
            break;
            case 3:
                $funding = new FundingOrder();
                $return_notity = $funding->PayNotity($yesno,$pay_type,$notity_data);
            break;
            case 4:
                $community = new CommunityModel();
                $return_notity=$community->PayNotity($yesno,$pay_type,$notity_data);
            break;
            case 5:
                $subscribe = new Subscribe();
                $return_notity=$subscribe->PayNotity($yesno,$pay_type,$notity_data);
            break;
            case 6:
                $store_order = new StoreOrder();
                $return_notity=$store_order->PayNotity($yesno,$pay_type,$notity_data);
            break;
            case 7:
                $store_order = new StoreOrder();
                $return_notity=$store_order->PayNotity($yesno,$pay_type,$notity_data);
            break;
            case 8:
                $property_subscribe = new PropertySubscribe();
                $return_notity=$property_subscribe->PayNotity($yesno,$pay_type,$notity_data);
            break;
            default:
            break;
        }
        //业务逻辑处理成功后
        if($return_notity)
        {
            //更新支付成功数据 
            $pay_db=new PayDb();
            $data['payed']=2;
            $data['transaction_id']=empty($this->pay->request_data['transaction_id'])?"":$this->pay->request_data['transaction_id'];
            $pay_db->update_paystatus_data($order_id,$data);
        }
        return $return_notity;
    }
    
    /**
     * 退款回调处理
     */
    public function RefundNotity($pay_platform=0,$yesno=0,$order_type=0,$order_id=0,$refund_id=0)
    {
        $return_notity=false;
        $notity_data=['base_data'=>[],'other_data'=>[]];
        $pay_type=0;
        Log::info("RefundNotity111:余额退款回调".$order_type);
        //处理余额回调
        if($pay_platform==1)
        {
            $yesno=1;
            $pay_type=1;
            $base_data=$this->getRefundBaseData($order_id,$refund_id);
            //Log::info('refund_base_data:', $base_data);
            $notity_data['base_data']=$base_data;
            $notity_data['other_data']=[];

            $pay_type=0;
            $refund_coin_fee=0;
            $refund_balance_fee=0;
             if($base_data['refund_balance_fee']>0)
             {
                 $pay_type=1;   
                 $refund_balance_fee=bcdiv($base_data['refund_balance_fee'],100,2);
             }
             if($base_data['refund_coin_fee']>0)
             {
                 $pay_type=2;     
                 $refund_coin_fee=bcdiv($base_data['refund_coin_fee'],100,2);
             }
             if($base_data['refund_balance_fee']>0 && $base_data['refund_coin_fee']>0 )
             {
                 $pay_type=3; 
                 $refund_balance_fee=bcdiv($base_data['refund_balance_fee'],100,2);
                 $refund_coin_fee=bcdiv($base_data['refund_coin_fee'],100,2);
             }
             Log::info("RefundNotity:余额退款回调66".$refund_balance_fee);
             $virtual_pay=new VirtualPay();
             $return_id=$virtual_pay->update_user_virtual($base_data['user_id'],'',1,$pay_type,$refund_balance_fee,$refund_coin_fee,1,$base_data['order_id'],$base_data['remark']);
             Log::info("RefundNotity:余额退款回调777_".$return_id);
             //平台支付失败，分发到业务逻辑失败
             if($return_id==-1)
             {
                 $yesno=2;
             }
        }

        //处理微信回调
        if($pay_platform==2)
        {
            $this->pay=new WxPay();
            //验证签名信息
            $yesno=$this->pay->check_refund_notify();
            //验证成功,分发回调数据到具体业务逻辑
            Log::info("微信退款回调签名结果".$this->pay->notice_result_msg);

            if($yesno==true)
            {
                Log::info("微信退款回调数据数组".print_r($this->pay->request_data,true));
                $yesno=1;
                $pay_type=2;
                $base_data=$this->getRefundBaseData($this->pay->request_data['out_trade_no'],$this->pay->request_data['out_refund_no']);
                if(empty($base_data))
                {
                    $yesno=2;
                }
                $notity_data['base_data']=$base_data;
                $notity_data['other_data']=$this->pay->request_data;
                $order_type=$this->pay->request_data['attach'];
                Log::info("平台退款回调数据数组".print_r($notity_data,true));
                //判断是否需要调用平台支付系统，平台目前优先余额、金币强制全额支付
                //平台支付系统成功，把成功信息分发到业务，如果失败，分发错误信息
                //具体业务逻辑处理成功，则返回微信成功信息
                $pay_type=0;
                if($base_data['refund_balance_fee']>0)
                {
                    $pay_type=1;
                    $refund_balance_fee=bcdiv($base_data['refund_balance_fee'],100,2);     
                }
                if($base_data['refund_coin_fee']>0)
                {
                    $pay_type=2;     
                    $refund_coin_fee=bcdiv($base_data['refund_coin_fee'],100,2);
                }
                if($base_data['refund_balance_fee']>0 && $base_data['refund_coin_fee']>0 )
                {
                    $pay_type=3; 
                    $refund_balance_fee=bcdiv($base_data['refund_balance_fee'],100,2);
                    $refund_coin_fee=bcdiv($base_data['refund_coin_fee'],100,2);
                }
                if($pay_type!=0)
                {
                    $virtual_pay=new VirtualPay();
                    $return_id=$virtual_pay->update_user_virtual($base_data['user_id'],'',1,$pay_type,$refund_balance_fee,$refund_coin_fee,1,$base_data['order_id'],$base_data['remark']);
                    //平台支付失败，分发到业务逻辑失败
                    if($return_id==-1)
                    {
                        $yesno=2;
                    }
                }
            }
            //返回微信错误信息
        }
        
        Log::info("RefundNotify: order_type:" . $order_type);
         //回调分发 订单类型  1 商品 2 拼团 3 众筹 4 活动 5 装修 6 线下购 7线上预约 8 楼盘认筹
         switch ($order_type)
         {
            case 1:
                $return_service = new OrderReturnService();
                $return_service->RefundNotity($yesno, $pay_type, $notity_data);
                // $order = new Order();
                // $return_notity=$order->RefundNotity($yesno,$pay_type,$notity_data);
            break;
            case 2:
                $group = new GroupOrderModel();
                $return_notity=$group->RefundNotity($yesno,$pay_type,$notity_data);
                Log::info("拼团:".$yesno.$pay_type.print_r($notity_data,true));
            break;
            case 3:
                $funding = new FundingOrder();
                $return_notity = $funding->RefundNotity($yesno,$pay_type,$notity_data);
            break;
            case 4:
                $community = new RefundcoModel();
                $return_notity=$community->RefundNotity($yesno,$pay_type,$notity_data);
            break;
            case 5:
                $subscribe = new RefundModel();
                $return_notity=$subscribe->RefundNotity($yesno,$pay_type,$notity_data);
            break;
            case 6:
                $store_order = new \app\store\model\StoreOrder();
                $return_notity=$store_order->RefundNotity($yesno,$pay_type,$notity_data);
            break;
            case 7:
                $store_order = new \app\store\model\StoreOrder();
                $return_notity=$store_order->RefundNotity($yesno,$pay_type,$notity_data);
            break;
            case 8:
                $property_subscribe = new PropertySubscribe();
                $return_notity=$property_subscribe->RefundNotity($yesno,$pay_type,$notity_data);
            break;
            default:
            break;
         }
         
        //更新退款成功数据 
        $pay_db=new PayDb();
        $data['refunded']=2;
        $data['transaction_id']=empty($this->pay->request_data['transaction_id'])?"":$this->pay->request_data['transaction_id'];
        $pay_db->update_refundstatus_data($order_id,$refund_id,$data);
          //业务逻辑处理成功后

        if($return_notity)
        {
            //退款完成后，解锁释放冻结的返利的余额、金币
            $distribution=new Distribution();
            $distribution->unlock_virtual($order_type,$order_id,2);
        }
         return $return_notity;
    }

}
